Change the generation strategy from code to type descriptors. This changes the way marshalling/unmarshalling is done. Previously the code generator would produce a C function for each structure. With this change, the layout of a structure is encoded in an array of bytes, and a piece of generic code traverses the array and performs the required operations. The main reason to do this is a reduced footprint, at the expense of some marshal/unmarshal overhead (but the TPM is so slow that the impact of this overhead should be negligible). Version with generated marshallers: semenzato@semenzato:~/trunks$ size tpmc text data bss dec hex	filename 188243 4172 48 192463 2efcf	tpmc version with interpreter-based marshalling: semenzato@semenzato:~/trunks$ size tpmc text data bss dec hex	filename 64655 8404 48 73107 11d93	tpmc Both of them contain the marshalling/unmarshalling code for all commands. For a small subset of commands, the generated-code version is probably still smaller, but the interpreted version is small enough that this won't be a concern even in the firmware. This change also adds the command TPM_GetTestResults. BUG=chromium-os:19488 TEST=none Change-Id: I2f5b30b480a0efcc4aa3db280aab20ec25681bab Reviewed-on: https://gerrit.chromium.org/gerrit/37040 Reviewed-by: Darren Krahn <dkrahn@chromium.org> Commit-Queue: Luigi Semenzato <semenzato@chromium.org> Tested-by: Luigi Semenzato <semenzato@chromium.org> 
diff --git a/Makefile b/Makefile index dec5e10..089ffab 100644 --- a/Makefile +++ b/Makefile 
@@ -2,7 +2,7 @@  # Use of this source code is governed by a BSD-style license that can be  # found in the LICENSE file.   -CFLAGS = -Wall -Werror -g -fPIC +CFLAGS = -Wall -Werror -g    CONVERTERS_H = \  g_tpm_commands.h \ @@ -14,14 +14,13 @@    CONVERTERS = $(CONVERTERS_H) $(CONVERTERS_C)   -LIBOBJECTS = \ -	ttl_authorization.o \ -	ttl_error_messages.o \ -	ttl_commands.o \ -	ttl_linux.o \ -  CSOURCES = \ -	$(LIBOBJECTS:.o=.c) \ +	ttl_authorization.c \ +	ttl_error_messages.c \ +	ttl_commands.c \ +	ttl_interpret.c \ +	ttl_linux.c \ +	ttl_marshal.c \ 	tpmc.c \    HSOURCES = \ @@ -32,15 +31,14 @@ 	ttl_error_messages.h \ 	ttl_marshal.h \   -all: tpmc ttl-test libtrunks.a +all: tpmc ttl-test    clean: -	rm -rf *.o g_* tpmc ttl-test test/{structure,command}.{c,h} libtrunks.a +	rm -rf *.o g_* tpmc ttl-test test/{structure,command}.{c,h}    $(CONVERTERS): g_tpm.phony   -g_tpm.phony: ttl_generator.py g_tpm_commands_structure.txt tss_tpm_h \ - command_list +g_tpm.phony: ttl_generator.py g_tpm_commands_structure.txt tss_tpm_h 	./ttl_generator.py 	touch g_tpm.phony   @@ -54,6 +52,3 @@  ttl-test: $(CONVERTERS_C) $(CSOURCES) $(HSOURCES) 	$(CC) -DTESTING $(CFLAGS) $(CONVERTERS_C) $(CSOURCES) -o ttl-test \ 	-lcrypto - -libtrunks.a: $(LIBOBJECTS) $(CONVERTERS:.c=.o) -	gcc -shared -Wl,-soname,libtrunks.so.1 -o libtrunks.so.1.0.1 $? 
diff --git a/command_list b/command_list index 13e8926..aa44f85 100644 --- a/command_list +++ b/command_list 
@@ -28,3 +28,4 @@  TPM_TakeOwnership  TPM_OwnerClear  TPM_ChangeAuthOwner +TPM_GetTestResult 
diff --git a/tpmc.c b/tpmc.c index 65e0099..8644e6c 100644 --- a/tpmc.c +++ b/tpmc.c 
@@ -415,6 +415,29 @@  return TtlChangeAuthOwner(TPM_ET_SRK, old_pwd_hash, new_pwd_hash);  }   +static uint32_t HandlerGetTestResult(void) { + uint8_t test_result[TPM_MAX_COMMAND_LENGTH]; + uint32_t test_result_length; + uint32_t result; + int i; + + if (nargs != 2) { + fprintf(stderr, "usage: tpmc gettest\n"); + exit(OTHER_ERROR); + } + + result = TtlGetTestResult(&test_result_length, test_result); + if (result != 0) { + return result; + } else { + for (i = 0; i < test_result_length; i++) { + printf("%02x", test_result[i]); + } + printf("\n"); + } + return 0; +} +  /* Table of TPM commands.  */  command_record command_table[] = { @@ -461,6 +484,8 @@  { "takeownership", "own", "take ownership of the TPM", HandlerTakeOwnership },  { "write", "write", "write to a space (write <index> [<byte0> <byte1> ...])",  HandlerWrite }, + { "gettestresult", "gettest", "print self test result (in hex)", + HandlerGetTestResult },  };    static int n_commands = sizeof(command_table) / sizeof(command_table[0]); @@ -471,9 +496,8 @@  0, 0, 0, 12,  0, 0, 0, TPM_ORD_Startup,  0, TPM_ST_CLEAR }; - uint32_t result;  printf("Running Trunks test\n"); - result = TtlStartup(); + (void) TtlStartup();  if (memcmp(TtlTestCommandBuffer, bytes, sizeof(bytes)) != 0) {  printf("Trunks test failed\n");  exit(1); 
diff --git a/trunks.h b/trunks.h index d8b7cee..af00d2e 100644 --- a/trunks.h +++ b/trunks.h 
@@ -55,5 +55,6 @@  uint32_t TtlOSAP(APSession* session, uint8_t* secret,  uint16_t entity_type, uint32_t entity_value);  uint32_t TtlOIAP(APSession* session, uint8_t* secret); +uint32_t TtlGetTestResult(uint32_t* length, uint8_t* test_result);    #endif /* TRUNKS_TRUNKS_H */ 
diff --git a/trunks_internal.h b/trunks_internal.h index 6ea661f..e515ab1 100644 --- a/trunks_internal.h +++ b/trunks_internal.h 
@@ -13,6 +13,9 @@  #include "ttl_marshal.h"  #include "ttl_authorization.h"   +/* The number of fields of a TPM structure must fit in a byte. */ +#define TTL_RECORD_FIELDS_MAX 255 +  #define TTLDEBUG(args) do { } while (0)  #define assert(condition) do { if (!(condition)) { \  TtlError("assertion " # condition " failed"); \ @@ -23,15 +26,80 @@  if (_result_ != TPM_SUCCESS) return _result_; \  } while (0)   +/* Bytecodes. See ttl_interpret.c for bytecode definitions. */ + +enum { + /* type descriptors */ + BC_INT64 = 8, /* don't start at 0 */ + BC_INT32 = 9, + BC_INT16 = 10, + BC_INT8 = 11, + BC_RECORD = 12, + BC_ARRAY = 13, + BC_REF = 14, + + /* field descriptors */ + BC_FIELD_KIND_NORMAL = 15, + BC_FIELD_KIND_VARIABLE = 16, + BC_ARRAYFIELD = 17, +}; + +/* Variable-length integers for bytecodes. The MSB is a continuation bit, the + * other 7 bits are a hecataicosaoctal digit (pardon my Greek). When the MSB + * is 1, there are other less significant bytes following this one. E.g.: { + * 0x81, 0x02 } = 128 + 2 = 130 */ + +#define BC_VLINT_CONTINUED 0x80 +#define BC_VLINT_MASK 0x7f + +/* Returns the offset of FIELD in STRUCT. */ +#define OFFSETOF(field, struct) \ + (((uint8_t *) &((struct *) 0)->field) - (uint8_t *) 0) + +/* Expands X as two bytes (MSB first) for use in a byte array initializer, with + * 0 <= X <= 65535 (not checked) */ +#define TWO_BYTES_INT(x) x / 256, x % 256 + +/* Produces two bytes containing the offset of FIELD in STRUCT for use in a + * byte array initializer (MSB first) */ +#define OFFSETOF_TWO_BYTES(field, struct) TWO_BYTES_INT(OFFSETOF(field, struct)) + +/* Array containing all byte codes. */ +extern uint8_t StructureByteCodes[]; +  /* Outputs an error message and quits. */  void TtlError(const char* format, ...);    /* Opens the TPM device. Returns TPM_SUCCESS or an error code. */  uint32_t TtlOpenDevice(void); +  /* Sends a request datagram to the TPM and receives a response. */  uint32_t TtlExecute(uint8_t* buffer, const uint32_t cmd_len,  const uint32_t buf_len, uint32_t* read_bytes);   +/* Executes a TPM command */ +uint32_t TtlRunCommand(uint32_t command_ordinal, + int rqu_index, int rsp_index, + void* rqu_struct, void* rsp_struct, + void* auth1, void* auth2, + uint8_t* buffer, const uint32_t buffer_size); + + +/* Returns a bytecode address given a bytecode index. */ +static inline uint8_t* ByteCodeIndexToAddress(int i) { + return &StructureByteCodes[i]; +} + +/* Marshals a TPM structure. CODEP is a bytecode passed by reference and advanced to the end of the code for the structure. CURSOR is a pointer to the outgoing buffer, also advanced after marshalling the data. FROM is a pointer */ +void TtlMarshal(uint8_t** codep, uint8_t** cursor, void* from); + +/* Unmarshals a TPM structure. */ +void TtlUnmarshal(uint8_t** codep, uint8_t** cursor, void* to); + +/* Computes the size of a TPM structure. */ +int TtlSizeCalc(uint8_t** codep, void* data); + +  #ifdef TESTING  extern uint8_t TtlTestCommandBuffer[];  #endif 
diff --git a/ttl_authorization.c b/ttl_authorization.c index 60642a9..65c60d2 100644 --- a/ttl_authorization.c +++ b/ttl_authorization.c 
@@ -97,7 +97,7 @@  the command header and all leading handles. */  uint8_t ordinal_buf[4];  uint8_t* ptr = ordinal_buf; - TtlMarshal_uint32_t(&ordinal, &ptr); + TtlMarshal_uint32_t(&ptr, &ordinal);  uint32_t params_offset = TPM_RSP_HEADER_SIZE +  ComputeRspParamHashOffset(ordinal);  SHA_CTX sha_ctx; @@ -132,9 +132,9 @@  ComputeReqParamsHash(cmd, cmd_length, ordinal, params_hash);  ComputeCmdAuth(auth, params_hash, auth_data);  /* Marshal authorization trailer. */ - TtlMarshal_uint32_t(&auth->handle, cursor); - TtlMarshal_TPM_NONCE(&auth->nonceOdd, cursor); - TtlMarshal_uint8_t(&auth->continueAuthSession, cursor); + TtlMarshal_uint32_t(cursor, &auth->handle); + TtlMarshal_TPM_NONCE(cursor, &auth->nonceOdd); + TtlMarshal_uint8_t(cursor, &auth->continueAuthSession);  memcpy(*cursor, auth_data, sizeof(auth_data));  *cursor += sizeof(auth_data);  } @@ -143,8 +143,8 @@  APSession* auth, uint8_t* cmd, uint32_t cmd_length,  uint32_t ordinal, uint8_t** cursor) {  /* Read authorization trailer. */ - TtlUnmarshal_TPM_NONCE(&auth->nonceEven, cursor); - TtlUnmarshal_uint8_t(&auth->continueAuthSession, cursor); + TtlUnmarshal_TPM_NONCE(cursor, &auth->nonceEven); + TtlUnmarshal_uint8_t(cursor, &auth->continueAuthSession);  uint8_t received_auth_data[TPM_SHA1_160_HASH_LEN];  memcpy(received_auth_data, *cursor, sizeof(received_auth_data));  *cursor += sizeof(received_auth_data); 
diff --git a/ttl_commands.c b/ttl_commands.c index 30b2127..d0daec5 100644 --- a/ttl_commands.c +++ b/ttl_commands.c 
@@ -206,7 +206,7 @@  request->capArea = cap;  request->subCapSize = 4;  request->subCap = subcap_cursor; - TtlMarshal_uint32_t(&subcap, &subcap_cursor); + TtlMarshal_uint32_t(&subcap_cursor, &subcap);  return Ttl_TPM_GetCapability(request, response, buffer,  TPM_MAX_COMMAND_LENGTH);  } @@ -304,7 +304,7 @@  if (result == TPM_SUCCESS) {  TPM_NV_DATA_PUBLIC nv_data;  uint8_t* cursor = response.resp; - TtlUnmarshal_TPM_NV_DATA_PUBLIC(&nv_data, &cursor); + TtlUnmarshal_TPM_NV_DATA_PUBLIC(&cursor, &nv_data);  *permissions = nv_data.permission.attributes;  }  return result; @@ -382,7 +382,7 @@  return TPM_BAD_KEY_PROPERTY;  }  cursor = inkey->algorithmParms.parms; - TtlUnmarshal_TPM_RSA_KEY_PARMS(&rsa_parms, &cursor); + TtlUnmarshal_TPM_RSA_KEY_PARMS(&cursor, &rsa_parms);  if (TtlSizeCalc_TPM_RSA_KEY_PARMS(&rsa_parms) !=  inkey->algorithmParms.parmSize) {  return TPM_BAD_PARAMETER; @@ -403,14 +403,14 @@  cursor = pkcs1_buffer;  *cursor++ = 0x30;  *cursor++ = 0x84; - TtlMarshal_uint32_t(&pkcs1_length, &cursor); + TtlMarshal_uint32_t(&cursor, &pkcs1_length);  *cursor++ = 0x02;  *cursor++ = 0x84; - TtlMarshal_uint32_t(&inkey->pubKey.keyLength, &cursor); + TtlMarshal_uint32_t(&cursor, &inkey->pubKey.keyLength);  TtlMarshal_Blob(inkey->pubKey.key, &cursor, inkey->pubKey.keyLength);  *cursor++ = 0x02;  *cursor++ = 0x84; - TtlMarshal_uint32_t(&rsa_parms.exponentSize, &cursor); + TtlMarshal_uint32_t(&cursor, &rsa_parms.exponentSize);  TtlMarshal_Blob(rsa_parms.exponent, &cursor, rsa_parms.exponentSize);  cursor = pkcs1_buffer;  outkey->rsa = d2i_RSAPublicKey(NULL, (const uint8_t**)&cursor, @@ -429,7 +429,7 @@  result = Ttl_TPM_ReadPubek(&request, &response, buffer, sizeof(buffer));  if (result == TPM_SUCCESS) {  uint8_t* cursor = digest; - TtlMarshal_TPM_PUBKEY(&response.pubEndorsementKey, &cursor); + TtlMarshal_TPM_PUBKEY(&cursor, &response.pubEndorsementKey);  TtlMarshal_Blob(request.antiReplay.nonce, &cursor,  sizeof(request.antiReplay.nonce));  SHA1(digest, cursor - digest, digest); @@ -504,7 +504,7 @@  rsa_parms.numPrimes = 2;  rsa_parms.exponentSize = 0;  cursor = rsa_parms_buffer; - TtlMarshal_TPM_RSA_KEY_PARMS(&rsa_parms, &cursor); + TtlMarshal_TPM_RSA_KEY_PARMS(&cursor, &rsa_parms);  request.srkParams.algorithmParms.parms = rsa_parms_buffer;  request.srkParams.PCRInfoSize = 0;  request.srkParams.pubKey.keyLength = 0; @@ -551,3 +551,16 @@  TtlFlushSpecific(auth.handle, TPM_RT_AUTH);  return result;  } + +uint32_t TtlGetTestResult(uint32_t *length, uint8_t *test_result) +{ + TPM_GetTestResult_rsp response; + uint8_t buffer[TPM_MAX_COMMAND_LENGTH]; + uint32_t result = Ttl_TPM_GetTestResult(&response, buffer, sizeof(buffer)); + if (result != 0) { + return result; + } + *length = response.outDataSize; + memcpy(test_result, response.outData, response.outDataSize); + return result; +} 
diff --git a/ttl_generator.py b/ttl_generator.py index fcdec66..48ffe36 100755 --- a/ttl_generator.py +++ b/ttl_generator.py 
@@ -7,7 +7,7 @@    """A code generator for TPM utility functions.   -The generator inputs the TCG header file "tpm.h" (here renamed +The generator inputs the Trousers header file "tpm.h" (here renamed  "tss_tpm_h") as well as massaged representation of TPM commands from  the TPM specs, and outputs marshalling/unmarshalling functions and  type declarations for the TPM structures and commands. @@ -42,8 +42,7 @@      # A dictionary of commands that are ignored. -IGNORED_COMMANDS = set(["TPM_FieldUpgrade", - "TPM_CertifySelfTest"]) +IGNORED_COMMANDS = set(["TPM_FieldUpgrade", "TPM_CertifySelfTest"])      # A set of struct declarations that are ignored. @@ -53,6 +52,78 @@  "TPM_KEY_HANDLE_LIST"])     +# Bytecodes + +BC_INT8 = "BC_INT8" +BC_INT16 = "BC_INT16" +BC_INT32 = "BC_INT32" +BC_REF = "BC_REF" +BC_ARRAY = "BC_ARRAY" +BC_RECORD = "BC_RECORD" +BC_FIELD_KIND_NORMAL = "BC_FIELD_KIND_NORMAL" +BC_FIELD_KIND_VARIABLE = "BC_FIELD_KIND_VARIABLE" + +# This variable keeps track of bytecode positions +BYTECODE_OFFSET = 0 + +# Structures whose bytecode offset is required in hand-written C code. +MANUALLY_MARSHALLED_STRUCTS = set([ + "TPM_NONCE", + "TPM_NV_DATA_PUBLIC", + "TPM_PUBKEY", + "TPM_RSA_KEY_PARMS", + ]) + +# Variable-length integers (varints) are encoded as 7-bit digits, most +# significant first (big endian, for readability). Each digit is stored in a +# byte. The most significant bit is 1 when there are more digits, 0 otherwise. +# For instance: +# +# 4 -> 0x04 +# 257 -> 0x81, 0x01 +# +# We can use varints only for known integer values, for instance bytecode +# offsets. A bunch of values are only known at C compilation time. + +def IntToByteCode(x): + return IntToByteCode1(x / 128) + [x % 128] + + +def IntToByteCode1(x): + if x == 0: + return [] + else: + return IntToByteCode1(x / 128) + [x % 128 + 128] + + +def OutputVarInt(x, file): + global BYTECODE_OFFSET + file.write("/* (%04d) varint: %d */" % (BYTECODE_OFFSET, x)) + bytes = IntToByteCode(x) + file.write("".join(map(lambda x: " %d," % x, bytes))) + BYTECODE_OFFSET += len(bytes) + file.write("\n") + + +def OutputByte(byte, file): + global BYTECODE_OFFSET + file.write("/* (%04d) */ %s,\n" % (BYTECODE_OFFSET, str(byte))) + BYTECODE_OFFSET += 1 + + +def OutputTwoBytes(x, file): + global BYTECODE_OFFSET + file.write("/* (%04d) */ TWO_BYTES_INT(%s),\n" % (BYTECODE_OFFSET, str(x))) + BYTECODE_OFFSET += 2 + + +def OutputOffsetOf(field_name, record_name, file): + global BYTECODE_OFFSET + file.write("/* (%04d) */ OFFSETOF_TWO_BYTES(%s, %s),\n" % + (BYTECODE_OFFSET, field_name, record_name)) + BYTECODE_OFFSET += 2 + +  # We parse a C header file (MIDL, actually) and produce descriptors for each  # type defined by the header file. Then we use the descriptors to output  # useful code. @@ -67,13 +138,21 @@  # has an associated class, which is a subclass of TypeDesc. Other classes are  # used internally to type descriptors, as described below.  # -# At the time this comment was last updated, there were four kinds of types: -# built-in types, types defined by typedef, types defined by a struct -# declaration, and pointers. +# There are four kinds of types: built-in types, types defined by typedef, +# types defined by a struct declaration, and pointers.    class TypeDesc(object):  """Generic type desriptor.""" - pass + def __init__(self): + self.bytecode_offset = -1 + + def OutputByteCodeOffset(self, file): + OutputVarInt(self.bytecode_offset, file) + + def OutputByteCodeRef(self, file): + assert self.bytecode_offset >= 0 + OutputByte(BC_REF, file) + self.OutputByteCodeOffset(file)      class NamedTypeDesc(TypeDesc): @@ -90,23 +169,15 @@  class BuiltInTypeDesc(NamedTypeDesc):  """Desriptor for built-in types."""   - def __init__(self, name, size): + def __init__(self, name, bytecode):  super(BuiltInTypeDesc, self).__init__(name) - if isinstance(size, str): - self.size_expression = size - else: - self.size = size - self.size_expression = "%d" % size + self.bytecode = bytecode    def BaseType(self):  return self   - # pylint: disable-msg=W0613 - def SizeExpression(self, accessor): - return self.size_expression - - def Size(self): - return self.size + def OutputByteCodeRef(self, file): + OutputByte(self.bytecode, file)      class TypedefDesc(NamedTypeDesc): @@ -119,9 +190,6 @@  def BaseType(self):  return self.definition.BaseType()   - def SizeExpression(self, accessor): - return self.definition.SizeExpression(accessor) -  def OutputDeclarations(self, out_file):  # Type declaration only  out_file.write("typedef %s %s;\n" % (self.definition.name, self.name)) @@ -129,43 +197,32 @@  def OutputDefinitions(self, out_file):  pass   + def OutputByteCode(self, out_file): + pass   -class PointerDesc(TypeDesc): - """Pointer type (used in argument lists).""" + def OutputByteCodeRef(self, out_file): + self.definition.OutputByteCodeRef(out_file)   - def __init__(self, base_type): - super(PointerDesc, self).__init__() - self.base_type = base_type - - def Format(self): - return self.base_type.Format() + "*" - - -# A record (struct) type descriptor contains a list of field descriptors -# (unsurprisingly). There are a few variants of field descriptors, each -# encoded by a Python subclass (hey, OOP is not my idea). See the -# documentation for the FieldDesc class.    class RecordDesc(NamedTypeDesc):  """Descriptor for structs (also typedefs of structs, for simplicity)."""   - _MARSHAL_HEADER_FORMAT = "void TtlMarshal_%s(%s* record, uint8_t** cursorp)%s" - _UNMARSHAL_HEADER_FORMAT = ("void TtlUnmarshal_%s(%s* record, " - "uint8_t** cursorp)%s") - _SIZECALC_HEADER_FORMAT = "uint32_t TtlSizeCalc_%s(%s* record)%s" -  def BaseType(self):  return self   - def SizeExpression(self, accessor): - # The parens aren't necessary but they help debugging - size_list = map(lambda f: f.SizeExpression(accessor), self.fields) - return "(%s)" % " + ".join(size_list) + def OutputByteCode(self, out_file): + if self.fields: + bytecode_offset = BYTECODE_OFFSET + out_file.write("/* Record: %s */\n" % self.name) + OutputByte(BC_RECORD, out_file) + OutputByte(len(self.fields), out_file) + for field in self.fields: + field.OutputByteCode(out_file) + self.bytecode_offset = bytecode_offset    def OutputDeclarations(self, out_file):  if self.fields:  self.OutputTypeDeclaration(out_file) - self.OutputFunctionDeclarations(out_file)    def OutputTypeDeclaration(self, out_file):  out_file.write("\ntypedef struct %s {\n" % self.name) @@ -173,37 +230,6 @@  field.OutputFieldDeclaration(out_file)  out_file.write("} %s;\n\n" % self.name)   - def OutputFunctionHeader(self, out_file, header_format, suffix): - out_file.write(header_format % (self.name, self.name, suffix)) - - def OutputFunctionDeclarations(self, out_file): - self.OutputFunctionHeader(out_file, self._MARSHAL_HEADER_FORMAT, ";\n") - self.OutputFunctionHeader(out_file, self._UNMARSHAL_HEADER_FORMAT, ";\n") - self.OutputFunctionHeader(out_file, self._SIZECALC_HEADER_FORMAT, ";\n") - - def OutputDefinitions(self, out_file): - """Outputs the function definitions for the struct.""" - if not self.fields: - return - - # Marshaller - self.OutputFunctionHeader(out_file, self._MARSHAL_HEADER_FORMAT, " {\n") - if self.fields[0].name == "tag": - out_file.write(" record->tag = %s;\n" % self.TagName()) - for field in self.fields: - field.OutputMarshalCode(out_file) - out_file.write("}\n\n") - - # Unmarshaller - self.OutputFunctionHeader(out_file, self._UNMARSHAL_HEADER_FORMAT, " {\n") - for field in self.fields: - field.OutputUnmarshalCode(out_file) - out_file.write("}\n\n") - - # Size calculator - self.OutputFunctionHeader(out_file, self._SIZECALC_HEADER_FORMAT, " {\n") - out_file.write(" return %s;\n}\n\n" % self.SizeExpression("record->")) -  def TagName(self):  if self.name in _STRUCTURE_TAG_EXCEPTIONS:  return _STRUCTURE_TAG_EXCEPTIONS[self.name] @@ -220,97 +246,55 @@  payload type).  """   - def SizeExpression(self, accessor): - return self.type.SizeExpression("%s%s." % (accessor, self.name)) + def __init__(self, record, index): + # RECORD is the containing record descriptor, used to emit code that lets + # the C compiler compute field offsets. INDEX is the position of the field + # in the record, used to find the size field for variable-length fields. + self.record = record + self.index = index + self.size_field = None + + def OutputByteCode(self, out_file): + out_file.write("/* Field: %s */\n" % self.name) + OutputByte(BC_FIELD_KIND_NORMAL, out_file) + OutputOffsetOf(self.name, self.record.name, out_file) + self.type.OutputByteCodeRef(out_file)    def OutputFieldDeclaration(self, out_file):  out_file.write(" %s %s;\n" % (self.type.name, self.name))   - def OutputMarshalCode(self, out_file): - out_file.write(" TtlMarshal_%s(&record->%s, cursorp);\n" % - (self.type.BaseType().name, self.name))   - def OutputUnmarshalCode(self, out_file): - out_file.write(" TtlUnmarshal_%s(&record->%s, cursorp);\n" % - (self.type.BaseType().name, self.name)) - - -class VarFieldDesc(object): +class VarFieldDesc(FieldDesc):  """Descriptor for variable-length fields."""   - def SizeExpression(self, accessor): - element_size_expr = self.type.BaseType().SizeExpression(None) - size_field_expr = "%s%s" % (accessor, self.size_field_name) - if element_size_expr == "1": - return size_field_expr - else: - return "(%s * %s)" % (size_field_expr, element_size_expr) + def OutputByteCode(self, out_file): + out_file.write("/* Variable-length field: %s */\n" % self.name) + OutputByte(BC_FIELD_KIND_VARIABLE, out_file) + OutputOffsetOf(self.name, self.record.name, out_file) + OutputByte(self.size_field.index, out_file) + self.type.OutputByteCodeRef(out_file)    def OutputFieldDeclaration(self, out_file):  out_file.write(" %s* %s;\n" % (self.type.name, self.name))   - def OutputMarshalCode(self, out_file): - type_cast = "" - if self.type.BaseType().SizeExpression(None) != "1": - type_cast = "(uint8_t*)" - out_file.write((" TtlMarshal_Blob(%srecord->%s, " - "cursorp, %s);\n") % - (type_cast, self.name, self.SizeExpression("record->"))) - - def OutputUnmarshalCode(self, out_file): - type_cast = "" - if self.type.BaseType().SizeExpression(None) != "1": - type_cast = "(uint8_t**)" - out_file.write((" TtlUnmarshal_Blob(%s&record->%s, " - "cursorp, record->%s);\n") % - (type_cast, self.name, self.size_field_name)) -    class ImplicitVarFieldDesc(VarFieldDesc):  """Descriptor for implicit variable-length fields.""" + pass   - # pylint: disable-msg=W0613 - def SizeExpression(self, accessor): - assert self.name == "payloadData" - # TODO(semenzato): figure out size and fix this - return "4096" - - def OutputMarshalCode(self, out_file): - # TODO(semenzato): figure out size and fix this - out_file.write(" memcpy(record->%s, *cursorp, 4096);\n" % self.name) - out_file.write(" *cursorp += 4096") - - def OutputUnmarshalCode(self, out_file): - # TODO(semenzato): figure out size and fix this - out_file.write(" record->%s = *cursorp;\n" % self.name) - out_file.write(" *cursorp += 4096;\n") - - -class ArrayFieldDesc(object): +class ArrayFieldDesc(FieldDesc):  """Descriptor for fixed-length array (e.g. TPM_SaveContext, TPM_NONCE)."""   - # pylint: disable-msg=W0613 - def SizeExpression(self, accessor): - element_size_expr = self.element_type.SizeExpression(None) - assert element_size_expr == "1" # expecting byte arrays only - return self.length -  def OutputFieldDeclaration(self, out_file):  out_file.write(" %s %s[%s];\n" % (self.element_type.name,  self.name,  self.length))   - def OutputMarshalCode(self, out_file): - assert self.element_type.Size() == 1 - out_file.write(" memcpy(*cursorp, record->%s, %s);\n" % - (self.name, self.length)) - out_file.write(" *cursorp += %s;\n" % self.length) - - def OutputUnmarshalCode(self, out_file): - assert self.element_type.Size() == 1 - out_file.write(" memcpy(record->%s, *cursorp, %s);\n" % - (self.name, self.length)) - out_file.write(" *cursorp += %s;\n" % self.length) + def OutputByteCode(self, out_file): + out_file.write("/* Array field: %s */\n" % self.name) + OutputByte(BC_ARRAY, out_file) + OutputTwoBytes(self.length, out_file) + self.element_type.OutputByteCodeRef(out_file)      class ArgDesc(object): @@ -320,18 +304,30 @@  self.name = name     +class PointerDesc(TypeDesc): + """Pointer type (used in argument lists).""" + + def __init__(self, base_type): + super(PointerDesc, self).__init__() + self.base_type = base_type + + def Format(self): + return self.base_type.Format() + "*" + +  # The symbol table, i.e. a dictionary mapping type names to type descriptors.  # It is initialized here with the predefined types.  TYPES_DICT = dict( - BYTE=BuiltInTypeDesc("uint8_t", 1), - TSS_BOOL=BuiltInTypeDesc("uint8_t", 1), - BOOL=BuiltInTypeDesc("uint8_t", 1), - UINT16=BuiltInTypeDesc("uint16_t", 2), - UINT32=BuiltInTypeDesc("uint32_t", 4), - UINT64=BuiltInTypeDesc("uint64_t", 8), - APSession=BuiltInTypeDesc("APSession", "sizeof(APSession)"), - TPM_RESULT=BuiltInTypeDesc("TPM_RESULT", 4), - int=BuiltInTypeDesc("int", "sizeof(int)")) + BYTE=BuiltInTypeDesc("uint8_t", "BC_INT8"), + TSS_BOOL=BuiltInTypeDesc("uint8_t", "BC_INT8"), + BOOL=BuiltInTypeDesc("uint8_t", "BC_INT8"), + UINT16=BuiltInTypeDesc("uint16_t", "BC_INT16"), + UINT32=BuiltInTypeDesc("uint32_t", "BC_INT32"), + UINT64=BuiltInTypeDesc("uint64_t", "BC_INT64"), + APSession=BuiltInTypeDesc("APSession", "BC_APSESSION"), + TPM_RESULT=BuiltInTypeDesc("TPM_RESULT", "BC_INT32"), + int=BuiltInTypeDesc("int", "BC_INT32"), + )      class StructureParser(object): @@ -390,9 +386,11 @@    return types   - def ParseRecord(self, in_file, desc): + + def ParseRecord(self, in_file, record_desc):  """Parses the body of a TPM struct declaration (all but the first line)."""  fields_list = [] + i = 0  size_field_name = None  line = in_file.next() # skip open brace  while True: @@ -407,22 +405,26 @@  if match:  type_name = match.group(1) + match.group(3)  field_name = match.group(2) - field_desc = FieldDesc() + field_desc = FieldDesc(record_desc, i)  field_desc.name = field_name  field_desc.type = type_name - field_desc.size_field_name = size_field_name - size_field_name = None + if size_field_name: + size_field_index = next((f for f in xrange(len(fields_list)) + if fields_list[f].name == size_field_name)) + field_desc.size_field_index = size_field_index + size_field_name = None  fields_list.append(field_desc) + i = i + 1  continue    match = self._ENDSTRUCT_RE.search(line)  if match: - desc.fields = fields_list + record_desc.fields = fields_list  return      class StructureGenerator(object): - """TPM structure types and marshalling code generator.""" + """TPM structure types and marshaling code generator."""    def Generate(self, types, filename_h, filename_c):  """Generates the .c and .h file for the given types.""" @@ -443,7 +445,7 @@  h.write(_HEADER_FILE_GUARD_FOOTER % {"name": guard_name})  h.close()   - # Definitions (.c file) + # Bytecodes (.c file)  c = open(filename_c, "w")  c.write(_COPYRIGHT_HEADER)  c.write(""" @@ -452,10 +454,14 @@    #include "%s"  #include "trunks_internal.h" +#include "g_tpm_commands.h" + +uint8_t StructureByteCodes[] = {    """ % filename_h)  for t in types: - t.OutputDefinitions(c) + t.OutputByteCode(c) +  c.close()     @@ -475,9 +481,11 @@  out_file.write("\n")  self.OutputFunctionHeader(out_file, ";\n")   + def OutputByteCode(self, out_file): + self.request.OutputByteCode(out_file) + self.response.OutputByteCode(out_file) +  def OutputDefinitions(self, out_file): - self.request.OutputDefinitions(out_file) - self.response.OutputDefinitions(out_file)  self.OutputFunctionHeader(out_file, " {")  self.OutputFunctionBody(out_file)   @@ -496,133 +504,33 @@    def OutputFunctionBody(self, out_file):  """Outputs the function body for this command.""" - marshal_template = """\ - TtlMarshal_%s(%s, &cursor); -""" - compute_auth1_template = """\ - if (auth1 != NULL) { - TtlComputeAndMarshal_TPM_AUTH( - auth1, buffer, message_size - TPM_RQU_AUTH_SIZE, ordinal, &cursor); - } -""" - compute_auth2_template = """\ - if (auth2 != NULL) { - TtlComputeAndMarshal_TPM_AUTH( - auth1, buffer, message_size - 2*TPM_RQU_AUTH_SIZE, ordinal, &cursor); - TtlComputeAndMarshal_TPM_AUTH( - auth2, buffer, message_size - 2*TPM_RQU_AUTH_SIZE, ordinal, &cursor); - } -""" - unmarshal_template = """\ - TtlUnmarshal_%s(%s, &cursor); -""" - verify_auth1_template = """\ - if (auth1 != NULL) { - RETURN_ON_FAILURE(TtlUnmarshalAndVerify_TPM_AUTH( - auth1, buffer, message_size - TPM_RSP_AUTH_SIZE, ordinal, &cursor)); - } -""" - verify_auth2_template = """\ - if (auth2 != NULL) { - RETURN_ON_FAILURE(TtlUnmarshalAndVerify_TPM_AUTH( - auth1, buffer, message_size - 2*TPM_RSP_AUTH_SIZE, ordinal, &cursor)); - RETURN_ON_FAILURE(TtlUnmarshalAndVerify_TPM_AUTH( - auth2, buffer, message_size - 2*TPM_RSP_AUTH_SIZE, ordinal, &cursor)); - } -"""  body_template = """ - uint32_t return_code; - uint8_t* cursor = buffer; - uint32_t read_bytes; - TPM_TAG tag = %(tag)s; - uint32_t ordinal = %(ordinal)s; - uint32_t message_size = %(in_message_size)s; - if (message_size > buffer_size) return TPM_BAD_PARAM_SIZE; -%(marshal_header)s\ -%(marshal_params)s\ - RETURN_ON_FAILURE(TtlExecute(buffer, message_size, buffer_size, &read_bytes)); - cursor = buffer; -%(unmarshal_header)s\ - if (return_code != TPM_SUCCESS) return return_code; - if (message_size != read_bytes) return TPM_E_COMMUNICATION_ERROR; -%(unmarshal_params)s\ +%(initializers)s RETURN_ON_FAILURE(TtlRunCommand(%(ordinal)s, + %(rqu_bytecode)s, %(rsp_bytecode)s, in_parameters, out_parameters, + auth1, auth2, buffer, buffer_size));  return TPM_SUCCESS;  }    """ - # request header - in_message_size = "TPM_RQU_HEADER_SIZE" - if self.has_ins: - in_message_size += (" + TtlSizeCalc_%s(in_parameters)" % - self.request.name) - if self.has_auth2: - in_message_size += " + ((auth2 != NULL) ? 2*TPM_RQU_AUTH_SIZE : 0)" - elif self.has_auth1: - in_message_size += " + ((auth1 != NULL) ? TPM_RQU_AUTH_SIZE : 0)" - if self.has_auth2: - tag = "(auth2 != NULL) ? TPM_TAG_RQU_AUTH2_COMMAND : TPM_TAG_RQU_COMMAND" - elif self.has_auth1: - tag = "(auth1 != NULL) ? TPM_TAG_RQU_AUTH1_COMMAND : TPM_TAG_RQU_COMMAND" - else: - tag = "TPM_TAG_RQU_COMMAND" - marshal_header = [] - marshal_header.append(marshal_template % ("uint16_t", "&tag")) - marshal_header.append(marshal_template % ("uint32_t", "&message_size")) - marshal_header.append(marshal_template % ("uint32_t", "&ordinal")) - - # request parameters and trailer - marshal_params = [] - if self.has_ins: - marshal_params.append(marshal_template % - (self.request.name, "in_parameters")) - if self.has_auth2: - marshal_params.append(compute_auth2_template) - elif self.has_auth1: - marshal_params.append(compute_auth1_template) - - # response header - out_message_size = "TPM_RSP_HEADER_SIZE" - if self.has_outs: - out_message_size += (" + TtlSizeCalc_%s(out_parameters)" % - self.response.name) - if self.has_auth2: - out_message_size += " + ((auth2 != NULL) ? 2*TPM_RSP_AUTH_SIZE : 0)" - elif self.has_auth1: - out_message_size += " + ((auth1 != NULL) ? TPM_RSP_AUTH_SIZE : 0)" - unmarshal_header = [] - unmarshal_header.append(unmarshal_template % ("uint16_t", "&tag")) - unmarshal_header.append(unmarshal_template % ("uint32_t", "&message_size")) - unmarshal_header.append(unmarshal_template % ("uint32_t", "&return_code")) - # response parameters and trailer - unmarshal_params = [] - if self.has_outs: - unmarshal_params.append(unmarshal_template % - (self.response.name, "out_parameters")) - - # check size - unmarshal_params.append( - " if (message_size > buffer_size) return TPM_BAD_PARAM_SIZE;\n" + - " if (message_size != %s) return TPM_BAD_PARAM_SIZE;\n" - % out_message_size) - if self.has_auth2: - unmarshal_params.append(verify_auth2_template) - elif self.has_auth1: - unmarshal_params.append(verify_auth1_template) - # write function body + initializers = "" + if not self.has_ins: + initializers += " void* in_parameters = NULL;\n"  if not self.has_outs: - out_file.write("\n uint8_t buffer[TPM_MAX_COMMAND_LENGTH];") - out_file.write("\n uint32_t buffer_size = sizeof(buffer);") + initializers += " void* out_parameters = NULL;\n" + initializers += " uint8_t buffer[TPM_MAX_COMMAND_LENGTH];\n" + initializers += " int buffer_size = sizeof(buffer);\n" + if not self.has_auth1: + initializers += " void* auth1 = NULL;\n" + if not self.has_auth2: + initializers += " void* auth2 = NULL;\n" + + # write function body  out_file.write(body_template % { - "request_name": self.request.name, - "response_name": self.response.name, - "tag": tag, + "initializers": initializers,  "ordinal": self.ordinal, - "in_message_size": in_message_size, - "marshal_header": "".join(marshal_header), - "marshal_params": "".join(marshal_params), - "unmarshal_header": "".join(unmarshal_header), - "unmarshal_params": "".join(unmarshal_params), - }) + "rqu_bytecode": self.request.bytecode_offset, + "rsp_bytecode": self.response.bytecode_offset, + })      class CommandParser(object): @@ -691,11 +599,13 @@  def ParseCommandRR(self, f, regexp, name):  """Parses a request or response structure."""  fields = [] + i = 0 + record = RecordDesc(name)  while self._line:  match = regexp.search(self._line)  if not match:  break - field = FieldDesc() + field = FieldDesc(record, i)  field.name = match.group(2)  # For now assign the type name, not the descriptor, and resolve later.  # The type resolution also includes transforming a FIELD into a VARFIELD @@ -704,9 +614,9 @@  field.description = match.group(3)  field.size_field_name = None  fields.append(field) + i = i + 1  self.NextLine(f)   - record = RecordDesc(name)  record.fields = fields  return record   @@ -733,7 +643,7 @@  """Fixes the given command structures.    Args: - record: Command structure to be fixed. + record: structure to be fixed.    The following modifications are applied:  1. Replace type names in fields with their type descriptors @@ -745,24 +655,22 @@  return    new_fields = [] - previous_name = None + previous_old_field = None + previous_new_field = None    for field in record.fields:  match = Rewriter._POINTER_RE.match(field.type)  if not match:  match = Rewriter._ARRAY_RE.match(field.type)  if match: - new_field = VarFieldDesc() + new_field = VarFieldDesc(record, field.index)  new_field.name = field.name  new_field.type = TYPES_DICT[match.group(1)] - if not field.size_field_name: - new_field.size_field_name = previous_name - else: - new_field.size_field_name = field.size_field_name + new_field.size_field = previous_new_field  else:  match = Rewriter._FIXARRAY_RE.match(field.type)  if match: - new_field = ArrayFieldDesc() + new_field = ArrayFieldDesc(record, field.index)  element_type = TYPES_DICT[match.group(1)]  new_field.element_type = element_type  new_field.name = field.name @@ -772,7 +680,8 @@  new_field.type = TYPES_DICT[field.type]    new_fields.append(new_field) - previous_name = new_field.name + previous_old_field = field + previous_new_field = new_field    record.fields = new_fields   @@ -787,6 +696,12 @@  if not cmd.tag or not cmd.ordinal:  print "Could not extract tag or ordinal for command %s" % cmd.name   + def FixFields(self, fields, len): + fields = fields[3:len] + for field in fields: + field.index -= 3 + return fields +  def FixRequestHeaderAndTrailer(self, cmd):  """Fixes the request header and trailer according to the command type."""  req_params_len = len(cmd.request.fields) @@ -797,7 +712,8 @@  elif cmd.tag == "TPM_TAG_RQU_AUTH1_COMMAND":  req_params_len -= 5  cmd.has_auth1 = True - cmd.request.fields = cmd.request.fields[3:req_params_len] + # remove first three fields + cmd.request.fields = self.FixFields(cmd.request.fields, req_params_len)  cmd.has_ins = len(cmd.request.fields) > 0    def FixResponseHeaderAndTrailer(self, cmd): @@ -807,7 +723,7 @@  rsp_params_len -= 6  elif cmd.tag == "TPM_TAG_RQU_AUTH1_COMMAND":  rsp_params_len -= 3 - cmd.response.fields = cmd.response.fields[3:rsp_params_len] + cmd.response.fields = self.FixFields(cmd.response.fields, rsp_params_len)  cmd.has_outs = len(cmd.response.fields) > 0    def ComputeCommandArgs(self, cmd): @@ -826,9 +742,9 @@      class CommandGenerator(object): - """TPM command types and marshalling code generator.""" + """TPM command types and marshaling code generator."""   - def Generate(self, commands, filename_h, filename_c, command_list): + def Generate(self, commands, filename_h, filename_b, filename_c):  """Generates the .c and .h file for the given commands."""  h = open(filename_h, "w")  h.write(_COPYRIGHT_HEADER) @@ -838,18 +754,29 @@  #include "g_tpm_structures.h"  #include "trunks_internal.h"  """) + b = open(filename_b, "a") + b.write("\n\n/* Command Structures (request and response) */\n\n")  c = open(filename_c, "w")  c.write(_COPYRIGHT_HEADER)  c.write("""  #include "%s"    """ % filename_h) + # Output addresses of bytecodes for some struct types. + for name in MANUALLY_MARSHALLED_STRUCTS: + struct = TYPES_DICT[name] + h.write("#define TTL_%s_BYTECODE_OFFSET %d\n" % + (name, struct.bytecode_offset)) + h.write("\n") + # Output commands.  for command in commands: - if (not command_list) or (command.name in command_list): - command.OutputDeclarations(h) - command.OutputDefinitions(c) + command.OutputDeclarations(h) + command.OutputByteCode(b) + command.OutputDefinitions(c)  h.write(_HEADER_FILE_GUARD_FOOTER % {"name": guard_name})  h.close() + b.write("};\n") + b.close()  c.close()     @@ -861,54 +788,12 @@  tpm_structures, "g_tpm_structures.h", "g_tpm_structures.c")  tpm_commands = CommandParser().Parse("g_tpm_commands_structure.txt")  Rewriter().Rewrite(tpm_commands) - command_list_file = open("command_list") - command_list = dict() - for line in command_list_file: - if not line.startswith("#"): - command_list[line.rstrip()] = 1 - CommandGenerator().Generate( - tpm_commands, "g_tpm_commands.h", "g_tpm_commands.c", command_list) - - -def TestEqualFile(x, y): - xs = open(x, "r").read() - ys = open(y, "r").read() - if xs != ys: - print("expected:\n--- begin\n%s--- end\nactual:\n--- begin\n%s--- end" % - (xs, ys)) - exit(1) - + CommandGenerator().Generate(tpm_commands, "g_tpm_commands.h", + "g_tpm_structures.c", "g_tpm_commands.c")    def Test(): - os.chdir("test") - filename_prefix = "structure" - s_input = filename_prefix + ".input" - s_output_h = filename_prefix + ".h" - s_output_c = filename_prefix + ".c" - s_expected_h = filename_prefix + ".h.expected" - s_expected_c = filename_prefix + ".c.expected" - - tpm_structures = StructureParser().Parse(s_input) - for structure in tpm_structures: - Rewriter().FixTypes(structure) - StructureGenerator().Generate(tpm_structures, s_output_h, s_output_c) - - TestEqualFile(s_output_h, s_expected_h) - TestEqualFile(s_output_c, s_expected_c) - - filename_prefix = "command" - c_input = filename_prefix + ".input" - c_output_h = filename_prefix + ".h" - c_output_c = filename_prefix + ".c" - c_expected_h = filename_prefix + ".h.expected" - c_expected_c = filename_prefix + ".c.expected" - - commands = CommandParser().Parse(c_input) - Rewriter().Rewrite(commands) - CommandGenerator().Generate(commands, c_output_h, c_output_c, None) - - TestEqualFile(c_output_h, c_expected_h) - TestEqualFile(c_output_c, c_expected_c) + print "no tests yet" + exit(1)    # main program   
diff --git a/ttl_interpret.c b/ttl_interpret.c new file mode 100644 index 0000000..010addf --- /dev/null +++ b/ttl_interpret.c 
@@ -0,0 +1,501 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Byte code interpreter for marshalling/unmarshalling. + */ + +#include "trunks_internal.h" + +/* + * Bytecodes + * --------- + * + * Type descriptor: + * - type kind (byte) + * - (possibly) type-dependent data + * + * Type-dependent data for BC_TYPE: + * - byte index of type descriptor bytecode (2 bytes) + * + * Type-dependent data for BC_ARRAY: + * - array size (2 bytes) + * + * Type-dependent data for BC_RECORD: + * - number of fields (1 byte) + * - field bytecodes for field 0 + * - field bytecodes for field 1 + * ... + * + * Field bytecodes: + * - field kind (byte) + * - field offset in record (2 bytes) + * - (for variable-length fields:) field number for length field (1 byte) + * - type descriptor for field (usually leaf type or BC_TYPE) + * + */ + +/* Local declarations for recursion. */ + + +/* Functions that parse bytecodes take a bytecode pointer as a (reference) + * argument and advance it as a side effect. If you need to parse it more than + * once (why?), save the pointer first. + * + * The Ttl(Un)MarshalXXX functions also advance their *cursor args as they copy + * data into the command buffer. + */ + +/* Takes a two-byte bytecode and returns the integer it represents. */ + +static inline int BC2ByteToInt(uint8_t** codep) { + int n = (*codep)[0] * 256 + (*codep)[1]; + *codep += 2; + return n; +} + +static inline uint8_t* ByteCodeOffsetToPointer(uint8_t** codep) { + int offset = BC2ByteToInt(codep); + return ByteCodeIndexToAddress(offset); +} + +static int TtlSizeCalcVarfield(void* data, uint8_t* length_field_bc) { + uint8_t length_field_kind = *length_field_bc++; + int length_field_offset = BC2ByteToInt(&length_field_bc); + int length_field_type = *length_field_bc++; + int length; + assert(length_field_kind == BC_FIELD_KIND_NORMAL); + switch (length_field_type) { + /* A length field may only be an integer. */ + case BC_INT32: + length = *(uint32_t *) (data + length_field_offset); + break; + case BC_INT16: + length = *(uint16_t *) (data + length_field_offset); + break; + default: + TtlError("invalid type %d of length field", *length_field_bc); + break; + } + return length; +} + + +static int TtlSizeCalcField(uint8_t** codep, void* data, uint8_t** field_bcs) { + uint8_t *cp = *codep; + int field_kind = *cp++; + int field_offset = BC2ByteToInt(&cp); + int size; + + switch (field_kind) { + + case BC_FIELD_KIND_NORMAL: + size = TtlSizeCalc(&cp, data + field_offset); + break; + + case BC_FIELD_KIND_VARIABLE: { + int length_field_index = *cp++; + uint8_t* length_field_bc = field_bcs[length_field_index]; + size = TtlSizeCalcVarfield(data, length_field_bc); + break; + } + + default: + TtlError("invalid field kind %d", field_kind); + break; + } + + *codep = cp; + return size; +} + +static int TtlSizeCalcRecord(uint8_t** codep, void* data) { + uint8_t* field_bcs[TTL_RECORD_FIELDS_MAX]; + uint8_t *cp = *codep; + int size = 0; + int nfields = *cp++; + int i; + + for (i = 0; i < nfields; i++) { + field_bcs[i] = cp; + size += TtlSizeCalcField(&cp, data, field_bcs); + } + *codep = cp; + return size; +} + +static int TtlSizeCalcArray(uint8_t** codep) { + uint8_t *cp = *codep; + int size; + uint8_t* bogus = 0; + + assert(*cp == BC_INT8 || + *cp == BC_INT16 || + *cp == BC_INT32 || + *cp == BC_INT64); + size = TtlSizeCalc(&cp, &bogus); + *codep = cp; + return size; +} + + +int TtlSizeCalc(uint8_t** codep, void* data) { + uint8_t *cp = *codep; + int size; + + switch (*cp++) { + + case BC_INT64: + size = 8; + break; + + case BC_INT32: + size = 4; + break; + + case BC_INT16: + size = 2; + break; + + case BC_INT8: + size = 1; + break; + + case BC_REF: { + uint8_t* typecode; + typecode = ByteCodeOffsetToPointer(&cp); + size = TtlSizeCalc(&typecode, data); + break; + } + + case BC_ARRAY: + size = TtlSizeCalcArray(&cp); + break; + + case BC_RECORD: + size = TtlSizeCalcRecord(&cp, data); + break; + + default: + TtlError("unknown bytecode %d", *cp); + } + + *codep = cp; + return size; +} + + +static void TtlMarshalField(uint8_t** codep, uint8_t** cursor, void* from, + uint8_t** field_bcs) { + uint8_t *to = *cursor; + uint8_t *cp = *codep; + int field_kind = *cp++; + int field_offset = BC2ByteToInt(&cp); + + switch (field_kind) { + + case BC_FIELD_KIND_NORMAL: + TtlMarshal(&cp, &to, from + field_offset); + break; + + case BC_FIELD_KIND_VARIABLE: { + int length_field_index = *cp++; + uint8_t* length_field_bc = field_bcs[length_field_index]; + int length = TtlSizeCalcVarfield(from, length_field_bc); + TtlMarshal_Blob(*(uint8_t**)(((uint8_t*) from) + field_offset), + &to, length); + break; + } + + default: + TtlError("invalid field kind %d", field_kind); + break; + } + + *cursor = to; + *codep = cp; +} + + +static void TtlUnmarshalField(uint8_t** codep, uint8_t** cursor, void* to, + uint8_t** field_bcs) { + uint8_t *from = *cursor; + uint8_t *cp = *codep; + int field_kind = *cp++; + int field_offset = BC2ByteToInt(&cp); + + switch (field_kind) { + + case BC_FIELD_KIND_NORMAL: + TtlUnmarshal(&cp, &from, to + field_offset); + break; + + case BC_FIELD_KIND_VARIABLE: { + int length_field_index = *cp++; + uint8_t* length_field_bc = field_bcs[length_field_index]; + int length = TtlSizeCalcVarfield(to, length_field_bc); + TtlUnmarshal_Blob((uint8_t**) (((uint8_t*) to) + field_offset), + &from, length); + break; + } + + default: + TtlError("invalid field kind %d", field_kind); + break; + } + + *cursor = from; + *codep = cp; +} + + +static void TtlMarshalRecord(uint8_t** codep, uint8_t** cursor, void* from) { + int i; + uint8_t* to = *cursor; + uint8_t* cp = *codep; + uint8_t* field_bcs[TTL_RECORD_FIELDS_MAX]; + int nfields = *cp++; + + for (i = 0; i < nfields; i++) { + field_bcs[i] = cp; + TtlMarshalField(&cp, &to, from, field_bcs); + } + + *cursor = to; + *codep = cp; +} + + +static void TtlUnmarshalRecord(uint8_t** codep, uint8_t** cursor, void* to) { + int i; + uint8_t* from = *cursor; + uint8_t* cp = *codep; + uint8_t* field_bcs[TTL_RECORD_FIELDS_MAX]; + int nfields = *cp++; + + for (i = 0; i < nfields; i++) { + field_bcs[i] = cp; + TtlUnmarshalField(&cp, &from, to, field_bcs); + } + + *cursor = from; + *codep = cp; +} + + +static void TtlMarshalArray(uint8_t** codep, uint8_t** cursor, void* from) { + uint8_t* to = *cursor; + uint8_t* cp = *codep; + int size = BC2ByteToInt(&cp); + /* A fixed-size arrays is allocated inside the structure. */ + memcpy(to, (uint8_t*) from, size); + to += size; + *cursor = to; + *codep = cp; +} + + +static void TtlUnmarshalArray(uint8_t** codep, uint8_t** cursor, void* to) { + uint8_t* from = *cursor; + uint8_t* cp = *codep; + int size = BC2ByteToInt(&cp); + /* A fixed-size arrays is allocated inside the structure. */ + memcpy((uint8_t*) to, from, size); + from += size; + *cursor = from; + *codep = cp; +} + + +void TtlMarshal(uint8_t** codep, uint8_t** cursor, void* from) { + uint8_t *to = *cursor; + uint8_t *cp = *codep; + + switch (*cp++) { + + case BC_INT32: + TtlMarshal_uint32_t(&to, (uint32_t*) from); + break; + + case BC_INT16: + TtlMarshal_uint16_t(&to, (uint16_t*) from); + break; + + case BC_INT8: + TtlMarshal_uint8_t(&to, (uint8_t*) from); + break; + + case BC_REF: { + uint8_t* typecode = ByteCodeOffsetToPointer(&cp); + TtlMarshal(&typecode, &to, from); + break; + } + + case BC_ARRAY: + TtlMarshalArray(&cp, &to, from); + break; + + case BC_RECORD: + TtlMarshalRecord(&cp, &to, from); + break; + + default: + TtlError("unknown bytecode %d", *cp); + } + + *cursor = to; + *codep = cp; +} + + +void TtlUnmarshal(uint8_t** codep, uint8_t** cursor, void* to) { + uint8_t *from = *cursor; + uint8_t *cp = *codep; + + switch (*cp++) { + + case BC_INT32: + TtlUnmarshal_uint32_t(&from, (uint32_t*) to); + break; + + case BC_INT16: + TtlUnmarshal_uint16_t(&from, (uint16_t*) to); + break; + + case BC_INT8: + TtlUnmarshal_uint8_t(&from, (uint8_t*) to); + break; + + case BC_REF: { + uint8_t* typecode = ByteCodeOffsetToPointer(&cp); + TtlUnmarshal(&typecode, &from, to); + break; + } + + case BC_ARRAY: + TtlUnmarshalArray(&cp, &from, to); + break; + + case BC_RECORD: + TtlUnmarshalRecord(&cp, &from, to); + break; + + default: + TtlError("unknown bytecode %d", *cp); + } + + *cursor = from; + *codep = cp; +} + + +uint32_t TtlRunCommand(uint32_t command_ordinal, + int rqu_index, int rsp_index, + void* rqu_struct, void* rsp_struct, + void* auth1, void* auth2, + uint8_t* buffer, const uint32_t buffer_size) { + uint8_t* cursor = buffer; + TPM_TAG tag = auth1 == NULL ? TPM_TAG_RQU_COMMAND : + (auth2 == NULL ? TPM_TAG_RQU_AUTH1_COMMAND : TPM_TAG_RQU_AUTH2_COMMAND); + uint32_t message_size = TPM_RQU_HEADER_SIZE; + int auth_size = auth1 == NULL ? 0: + (auth2 == NULL ? TPM_RQU_AUTH_SIZE: 2 * TPM_RQU_AUTH_SIZE); + uint32_t read_bytes; + uint32_t return_code; + int expected_size; + + /* First compute message size to ensure buffer is large enough. */ + if (rqu_index >= 0) { + uint8_t* bytecode = ByteCodeIndexToAddress(rqu_index); + message_size += TtlSizeCalc(&bytecode, rqu_struct); + } + + message_size += auth_size; + + if (message_size > buffer_size) { + return TPM_BAD_PARAM_SIZE; + } + + /* Then marshal the various parts of the message. First the header. */ + TtlMarshal_uint16_t(&cursor, &tag); + TtlMarshal_uint32_t(&cursor, &message_size); + TtlMarshal_uint32_t(&cursor, &command_ordinal); + + /* Then the additional command parameters, if any. */ + if (rqu_index >= 0) { + uint8_t* bytecode = ByteCodeIndexToAddress(rqu_index); + TtlMarshal(&bytecode, &cursor, rqu_struct); + } + + /* Then the auths (if any) */ + if (auth1 != NULL) { + TtlComputeAndMarshal_TPM_AUTH(auth1, buffer, message_size - auth_size, + command_ordinal, &cursor); + if (auth2 != NULL) { + TtlComputeAndMarshal_TPM_AUTH(auth2, buffer, message_size - auth_size, + command_ordinal, &cursor); + } + } + + /* Check that the computed message size matches the actual size. This is an + * important consistency check, since we don't trust the bytecodes. */ + if (cursor - buffer != message_size) { + return TPM_E_INTERNAL_ERROR; + } + + /* Send the command to the TPM and receive a response. */ + RETURN_ON_FAILURE(TtlExecute(buffer, message_size, buffer_size, &read_bytes)); + cursor = buffer; + + /* Extract the response header. */ + TtlUnmarshal_uint16_t(&cursor, &tag); + TtlUnmarshal_uint32_t(&cursor, &message_size); + TtlUnmarshal_uint32_t(&cursor, &return_code); + + if (return_code != TPM_SUCCESS) { + return return_code; + } + if (message_size > buffer_size) { + /* Is message_size doesn't lie, we have a buffer overflow. Anything could + * happen. TODO(semenzato): the error code could be more specific. */ + return TPM_BAD_PARAM_SIZE; + } + if (message_size != read_bytes) { + return TPM_E_COMMUNICATION_ERROR; + } + + /* Extract the response parameters, if any */ + if (rsp_index >= 0) { + uint8_t* bytecode = ByteCodeIndexToAddress(rsp_index); + TtlUnmarshal(&bytecode, &cursor, rsp_struct); + } + + /* Compute the expected size of the command response, for a consistency + * check. */ + expected_size = TPM_RSP_HEADER_SIZE; + + if (rsp_index >= 0) { + uint8_t* bytecode = ByteCodeIndexToAddress(rsp_index); + expected_size += TtlSizeCalc(&bytecode, rsp_struct); + } + if (auth1 != NULL) { + expected_size += TPM_RSP_AUTH_SIZE; + } + + if (message_size != expected_size) { + /* This isn't necessarily our fault (if message size lies, for instance, + * then it may be a communication error) so we pick the most likely + * cause. */ + return TPM_E_INTERNAL_ERROR; + } + + /* Check the response auth. Do this last so that earlier unmarshalling or + * communication errors are reported more precisely. */ + if (auth1 != NULL) { + int auth_size = TPM_RSP_AUTH_SIZE; + RETURN_ON_FAILURE(TtlUnmarshalAndVerify_TPM_AUTH(auth1, buffer, + message_size - auth_size, + command_ordinal, &cursor)); + } + return TPM_SUCCESS; +} 
diff --git a/ttl_linux.c b/ttl_linux.c index 2aa76e0..d18c1d2 100644 --- a/ttl_linux.c +++ b/ttl_linux.c 
@@ -29,6 +29,7 @@  fprintf(stderr, "ERROR: ");  vfprintf(stderr, format, ap);  va_end(ap); + fprintf(stderr, "\n");  exit(1);  }   @@ -46,20 +47,19 @@  memcpy(TtlTestCommandBuffer, buffer, cmd_len);  #else  if (cmd_len > TPM_MAX_COMMAND_LENGTH) { - TtlError("invalid command length %d for command 0x%x\n", - cmd_len, buffer[9]); + TtlError("invalid command length %d for command 0x%x", cmd_len, buffer[9]);  } else if (tpm_fd < 0) { - TtlError("the TPM device was not opened\n"); + TtlError("the TPM device was not opened");  } else {  int n = write(tpm_fd, buffer, cmd_len);  if (n != cmd_len) { - TtlError("write failure to TPM device: %s\n", strerror(errno)); + TtlError("write failure to TPM device: %s", strerror(errno));  }  n = read(tpm_fd, buffer, buf_len);  if (n == 0) { - TtlError("null read from TPM device\n"); + TtlError("null read from TPM device");  } else if (n < 0) { - TtlError("read failure from TPM device: %s\n", strerror(errno)); + TtlError("read failure from TPM device: %s", strerror(errno));  }  *read_bytes = n;  } @@ -90,7 +90,7 @@    tpm_fd = open(device_path, O_RDWR);  if (tpm_fd < 0) { - TtlError("TPM: Cannot open TPM device %s: %s\n", + TtlError("TPM: Cannot open TPM device %s: %s",  device_path, strerror(errno));  }   
diff --git a/ttl_marshal.c b/ttl_marshal.c new file mode 100644 index 0000000..2ef9f02 --- /dev/null +++ b/ttl_marshal.c 
@@ -0,0 +1,65 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Marshalling/unmarshalling useful data structures. + */ + + +#include "trunks_internal.h" +#include "g_tpm_commands.h" + + +void TtlMarshal_TPM_NONCE(uint8_t** cursor, TPM_NONCE* nonce) { + uint8_t* code = ByteCodeIndexToAddress(TTL_TPM_NONCE_BYTECODE_OFFSET); + TtlMarshal(&code, cursor, nonce); +} + +void TtlUnmarshal_TPM_NONCE(uint8_t** cursor, TPM_NONCE* nonce) { + uint8_t* code = ByteCodeIndexToAddress(TTL_TPM_NONCE_BYTECODE_OFFSET); + TtlUnmarshal(&code, cursor, nonce); +} + +/* --- */ + +void TtlMarshal_TPM_NV_DATA_PUBLIC(uint8_t** cursor, TPM_NV_DATA_PUBLIC* ndp) { + uint8_t* code = + ByteCodeIndexToAddress(TTL_TPM_NV_DATA_PUBLIC_BYTECODE_OFFSET); + TtlMarshal(&code, cursor, ndp); +} + +void TtlUnmarshal_TPM_NV_DATA_PUBLIC(uint8_t** cursor, + TPM_NV_DATA_PUBLIC* ndp) { + uint8_t* code = + ByteCodeIndexToAddress(TTL_TPM_NV_DATA_PUBLIC_BYTECODE_OFFSET); + TtlUnmarshal(&code, cursor, ndp); +} + +/* --- */ + +void TtlMarshal_TPM_RSA_KEY_PARMS(uint8_t** cursor, TPM_RSA_KEY_PARMS* rkp) { + uint8_t* code = ByteCodeIndexToAddress(TTL_TPM_RSA_KEY_PARMS_BYTECODE_OFFSET); + TtlMarshal(&code, cursor, rkp); +} + +void TtlUnmarshal_TPM_RSA_KEY_PARMS(uint8_t** cursor, TPM_RSA_KEY_PARMS* rkp) { + uint8_t* code = ByteCodeIndexToAddress(TTL_TPM_RSA_KEY_PARMS_BYTECODE_OFFSET); + TtlUnmarshal(&code, cursor, rkp); +} + +int TtlSizeCalc_TPM_RSA_KEY_PARMS(TPM_RSA_KEY_PARMS* rkp) { + uint8_t* code = ByteCodeIndexToAddress(TTL_TPM_RSA_KEY_PARMS_BYTECODE_OFFSET); + return TtlSizeCalc(&code, rkp); +} + +/* --- */ + +void TtlMarshal_TPM_PUBKEY(uint8_t** cursor, TPM_PUBKEY* pk) { + uint8_t* code = ByteCodeIndexToAddress(TTL_TPM_PUBKEY_BYTECODE_OFFSET); + TtlMarshal(&code, cursor, pk); +} + +void TtlUnmarshal_TPM_PUBKEY(uint8_t** cursor, TPM_PUBKEY* pk) { + uint8_t* code = ByteCodeIndexToAddress(TTL_TPM_PUBKEY_BYTECODE_OFFSET); + TtlUnmarshal(&code, cursor, pk); +} 
diff --git a/ttl_marshal.h b/ttl_marshal.h index bb7bb00..582df5d 100644 --- a/ttl_marshal.h +++ b/ttl_marshal.h 
@@ -17,7 +17,7 @@  #define INLINE inline    POSSIBLY_UNUSED -static INLINE void TtlMarshal_uint64_t(const uint64_t* x, uint8_t** cursor) { +static INLINE void TtlMarshal_uint64_t(uint8_t** cursor, const uint64_t* x) {  /* Use local variables to remove aliasing concerns */  uint8_t* buffer = *cursor;  uint64_t y = *x; @@ -33,7 +33,7 @@  }    POSSIBLY_UNUSED -static INLINE void TtlUnmarshal_uint64_t(uint64_t* x, uint8_t** cursor) { +static INLINE void TtlUnmarshal_uint64_t(uint8_t** cursor, uint64_t* x) {  uint8_t* buffer = *cursor;  *x = (((uint64_t) buffer[0]) << 56) |  (((uint64_t)buffer[1]) << 48) | @@ -47,7 +47,7 @@  }    POSSIBLY_UNUSED -static INLINE void TtlMarshal_uint32_t(const uint32_t* x, uint8_t** cursor) { +static INLINE void TtlMarshal_uint32_t(uint8_t** cursor, const uint32_t* x) {  /* Use local variables to remove aliasing concerns */  uint8_t* buffer = *cursor;  uint32_t y = *x; @@ -59,7 +59,7 @@  }    POSSIBLY_UNUSED -static INLINE void TtlUnmarshal_uint32_t(uint32_t* x, uint8_t** cursor) { +static INLINE void TtlUnmarshal_uint32_t(uint8_t** cursor, uint32_t* x) {  uint8_t* buffer = *cursor;  *x = ((buffer[0] << 24) |  (buffer[1] << 16) | @@ -69,7 +69,7 @@  }    POSSIBLY_UNUSED -static INLINE void TtlMarshal_uint16_t(const uint16_t* x, uint8_t** cursor) { +static INLINE void TtlMarshal_uint16_t(uint8_t** cursor, const uint16_t* x) {  /* Use local variables to remove aliasing concerns */  uint8_t* buffer = *cursor;  uint16_t y = *x; @@ -79,7 +79,7 @@  }    POSSIBLY_UNUSED -static INLINE void TtlUnmarshal_uint16_t(uint16_t* x, uint8_t** cursor) { +static INLINE void TtlUnmarshal_uint16_t(uint8_t** cursor, uint16_t* x) {  uint8_t* buffer = *cursor;  *x = ((buffer[0] << 8) |  (buffer[1] << 0)); @@ -88,13 +88,13 @@      POSSIBLY_UNUSED -static INLINE void TtlMarshal_uint8_t(const uint8_t* x, uint8_t** cursor) { +static INLINE void TtlMarshal_uint8_t(uint8_t** cursor, const uint8_t* x) {  **cursor = *x;  *cursor += 1;  }    POSSIBLY_UNUSED -static INLINE void TtlUnmarshal_uint8_t(uint8_t* x, uint8_t** cursor) { +static INLINE void TtlUnmarshal_uint8_t(uint8_t** cursor, uint8_t* x) {  *x = **cursor;  *cursor += 1;  } @@ -107,17 +107,27 @@  #define TtlMarshal_UINT64(x, cursor) TtlMarshal_uint64_t(x, cursor)    POSSIBLY_UNUSED -static INLINE void TtlMarshal_Blob(const uint8_t* x, +static INLINE void TtlMarshal_Blob(const uint8_t* from,  uint8_t** cursor, int size) { - memcpy(*cursor, x, size); + memcpy(*cursor, from, size);  *cursor += size;  }    POSSIBLY_UNUSED -static INLINE void TtlUnmarshal_Blob(uint8_t** x, +static INLINE void TtlUnmarshal_Blob(uint8_t** to,  uint8_t** cursor, int size) { - *x = *cursor; + *to = *cursor;  *cursor += size;  }   +void TtlMarshal_TPM_NONCE(uint8_t** cursor, TPM_NONCE* nonce); +void TtlUnmarshal_TPM_NONCE(uint8_t** cursor, TPM_NONCE* nonce); +void TtlMarshal_TPM_NV_DATA_PUBLIC(uint8_t** cursor, TPM_NV_DATA_PUBLIC* ndp); +void TtlUnmarshal_TPM_NV_DATA_PUBLIC(uint8_t** cursor, TPM_NV_DATA_PUBLIC* ndp); +void TtlMarshal_TPM_RSA_KEY_PARMS(uint8_t** cursor, TPM_RSA_KEY_PARMS* rkp); +void TtlUnmarshal_TPM_RSA_KEY_PARMS(uint8_t** cursor, TPM_RSA_KEY_PARMS* rkp); +int TtlSizeCalc_TPM_RSA_KEY_PARMS(TPM_RSA_KEY_PARMS* rkp); +void TtlMarshal_TPM_PUBKEY(uint8_t** cursor, TPM_PUBKEY* pk); +void TtlUnmarshal_TPM_PUBKEY(uint8_t** cursor, TPM_PUBKEY* pk); +  #endif /* TRUNKS_TPM_MARSHAL_H_ */